﻿using System.Collections;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Text;


public class AssetBundlePack
{
    /// <summary>需要打包的资源路径</summary>
    private static string SourcePath = AssetBundleConfig.AssetBundleSourcePath;

    /// <summary>打包后的AssetBundle存放路径</summary>
    private static string AssetBundlesOutputPath = AssetBundleConfig.AssetBundlesOutputPath;

    /// <summary>MD5文件名</summary>
    private static string HashCodeFileName = AssetBundleConfig.HashCodeFileName;


    [MenuItem("AssetBundle/CheckFilesRule 检测规则", false, 100)]
    public static void CheckFileRule()
    {
        if (CheckCanPack(SourcePath, true))
        {
            Debug.Log("文件组织正确");
        }
        else
        {
            Debug.Log("文件组织失败，修复后才能打包   ");
        }
    }

    [MenuItem("AssetBundle/BuildAssetBundle_Android 打AssetBundle包", false, 201)]
    public static void BuildAndroid()
    {
        BuildAssetBundle(RuntimePlatform.Android);
    }

    [MenuItem("AssetBundle/BuildAssetBundle_IOS 打AssetBundle包", false, 202)]
    public static void BuildIOS()
    {
        BuildAssetBundle(RuntimePlatform.IPhonePlayer);
    }

    [MenuItem("AssetBundle/BuildAssetBundle_Windows 打AssetBundle包", false, 203)]
    public static void BuildWindows()
    {
        BuildAssetBundle(RuntimePlatform.WindowsEditor);
    }

    [MenuItem("AssetBundle/AutoPackAssetBundle 一键打包", false, 701)]
    public static void AutoPackAssetBundle()
    {
        // 打开下载面板
    }

    private static void BuildAssetBundle(RuntimePlatform build_target)
    {
        // 清理AssetBundlesName
        ClearAssetBundlesName();

        // 重新设置AssetBundleName
        if (CheckCanPack(SourcePath))
        {
            Pack(SourcePath);
        }
        else
        {
            Debug.Log("文件组织形式设置不正确，打包已经被中断");
            return;
        }

        // 路径设置检测
        string outputPath = FileTool.PathCombine(AssetBundlesOutputPath, Platform.GetPlatformFolder(build_target));
        if (!Directory.Exists(outputPath))
        {
            Directory.CreateDirectory(outputPath);
        }
        
        // 打包
        BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.None, Platform.ChangeRuntimePlatformToBuildTarget(build_target));

        // 生成hashCode
        // 根据build_target平台进行打包  
        var replace_str = FileTool.ReplacePathSign(Application.dataPath);
        var _outputPath = outputPath.Replace(replace_str, "");
        if (_outputPath.StartsWith("/"))
        {
            _outputPath = _outputPath.Remove(0, 1);
        }
        _outputPath = "Assets/" + _outputPath;
        var manifest_bundle = Platform.GetPlatformFolder(build_target);
        SaveHashCode(_outputPath, manifest_bundle);

        AssetDatabase.Refresh();

        Debug.Log("打包完成");
    }

    // 存储hash_code
    private static void SaveHashCode(string out_dir_path, string manifest_bundle)
    {
        var manifest_name = out_dir_path + "/" + manifest_bundle;
        var bundle = AssetBundle.LoadFromFile(manifest_name);
        var mainfest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");


        StringBuilder builder = new StringBuilder();

        // 创建manifest的MD5 使用.Net提供的API
        var r_stream = new FileStream(manifest_name, FileMode.Open);
        System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
        var vals = md5.ComputeHash(r_stream);
        StringBuilder sBuilder = new StringBuilder();
        CombineContent(sBuilder, manifest_bundle, null);
        foreach (var val in vals) sBuilder.Append(val.ToString("x2"));
        builder.Append(sBuilder.ToString());
        FileTool.CloseStream(r_stream);

        // 创建其它的AssetBundle创建HashCode 使用Unity自己的API
        var names = AssetDatabase.GetAllAssetBundleNames();
        var len = names.Length;
        for (int i = 0; i < len; ++i)
        {
            var bundle_name = names[i];
            var hash_code = mainfest.GetAssetBundleHash(bundle_name);

            // 构造 存储格式   格式 => name=hashcode[\n]
            CombineContent(builder, bundle_name, hash_code.ToString(), "\n");
        }

        // 拼接成为文本
        var content = builder.ToString();
        var hash_code_path = out_dir_path + "/" + HashCodeFileName;
        FileTool.WriteFileContent(hash_code_path, content);
    }

    private static void CombineContent(StringBuilder sb, string name, string content, string preface = null)
    {
        if (!string.IsNullOrEmpty(preface)) sb.Append(preface);
        if (!string.IsNullOrEmpty(name))
        {
            sb.Append(name);
            sb.Append("=");
        }
        if (!string.IsNullOrEmpty(content)) sb.Append(content);
    }

    /// <summary>  
    /// 清除之前设置过的AssetBundleName，避免产生不必要的资源也打包  
    /// 只要设置了AssetBundleName的，都会进行打包，不论在什么目录下  
    /// </summary>  
    static void ClearAssetBundlesName()
    {
        int length = AssetDatabase.GetAllAssetBundleNames().Length;
        Debug.Log(length);
        string[] oldAssetBundleNames = new string[length];
        for (int i = 0; i < length; i++)
        {
            oldAssetBundleNames[i] = AssetDatabase.GetAllAssetBundleNames()[i];
        }

        for (int j = 0; j < oldAssetBundleNames.Length; j++)
        {
            AssetDatabase.RemoveAssetBundleName(oldAssetBundleNames[j], true);
        }
        AssetDatabase.RemoveUnusedAssetBundleNames();
    }

    static void Pack(string source)
    {
        DirectoryInfo folder = new DirectoryInfo(source);
        FileSystemInfo[] files = folder.GetFileSystemInfos();
        int length = files.Length;
        for (int i = 0; i < length; i++)
        {
            if (files[i] is DirectoryInfo)
            {
                Pack(files[i].FullName);
            }
            else
            {
                if (!files[i].Name.EndsWith(".meta"))
                {
                    var full_name = files[i].FullName;
                    var bundle_name = GetAssetBundleName(full_name);
                    SetAssetBundleName(full_name,bundle_name);
                }
            }
        }
    }

    static bool CheckCanPack(string source = "", bool is_print_log = false)
    {
        // 设置默认值
        if (string.IsNullOrEmpty(source)) source = SourcePath;

        DirectoryInfo folder = new DirectoryInfo(source);
        FileSystemInfo[] files = folder.GetFileSystemInfos();
        int length = files.Length;
        bool is_can_pack = true;

        // 文件组织规则：
        // 在当前目录中里面要么全部是子目录
        // 要么就全是子文件 .meta 文件例外

        // 将文件归类
        List<FileSystemInfo> _dirs = new List<FileSystemInfo>();
        List<FileSystemInfo> _files = new List<FileSystemInfo>();
        for (int i = 0; i < length; i++)
        {
            var list = files[i] is DirectoryInfo ? _dirs : _files;
            list.Add(files[i]);
        }

        // 查看目录是否全部是文件
        if (_files.Count > 0 && _dirs.Count > 0)
        {
            for (int i = 0; i < _files.Count; ++i)
            {
                // .meta文件是例外
                if (!_files[i].FullName.EndsWith(".meta"))
                {
                    is_can_pack = false;
                    if (is_print_log)
                    {
                        foreach (var __dir in _dirs)
                        {
                            Debug.Log(" 错误的文件组织： " + __dir.FullName);
                        }
                    }
                    break;
                }
            }
        }

        if (_dirs.Count > 0)
        {
            for (int i = 0; i < _dirs.Count; ++i)
            {
                is_can_pack = is_can_pack && CheckCanPack(files[i].FullName, is_print_log);
            }
        }

        return is_can_pack;
    }

    // 设置AssetBundleName策略
    static string GetAssetBundleName(string file_full_path)
    {
         Debug.Log("GetAssetBundleName   file_full_path: " + file_full_path);

        string set_path = "";

        // 一个图集一个包
        if (file_full_path.Contains("Atlas") || file_full_path.Contains("Atlases"))
        {
            var file_name = System.IO.Path.GetFileNameWithoutExtension(file_full_path);
            file_name = System.IO.Path.GetDirectoryName(file_full_path) + @"\" + file_name + ".unity3d";
            set_path = file_name;
        }
        // 一个prefab,一个scene 一个AssetBundle包
        else if (file_full_path.Contains("Prefabs") || file_full_path.Contains("Scenes"))
        {
            set_path = System.IO.Path.ChangeExtension(file_full_path, "unity3d");
        }
        else// 一个文件夹一个包
        {
            var dir_name = System.IO.Path.GetDirectoryName(file_full_path) + ".unity3d";
            set_path = dir_name;
        }

        string _source = FileTool.ReplacePathSign(set_path);
        string _assetPath2 = _source.Substring(Application.dataPath.Length + 1);
        string assetName = _assetPath2.Substring(_assetPath2.IndexOf("/") + 1);

         Debug.Log("GetAssetBundleName :  " + assetName);

        return assetName;
    }


    static void SetAssetBundleName(string source_full_path,string set_bundle_name)
    {
        // Debug.Log("SetAssetBundleName   source_full_path: " + source_full_path + "   set_bundle_name:  " + set_bundle_name);

        //在代码中给资源设置AssetBundleName  
        string _source = FileTool.ReplacePathSign(source_full_path);
        string _assetPath = "Assets" + _source.Substring(Application.dataPath.Length);
        var assetImporter = AssetImporter.GetAtPath(_assetPath);
        assetImporter.assetBundleName = set_bundle_name;
    }
}
